/*** 
 * @_______________#########_______________________ 
 * @______________############_____________________ 
 * @______________#############____________________ 
 * @_____________##__###########___________________ 
 * @____________###__######_#####__________________ 
 * @____________###_#######___####_________________ 
 * @___________###__##########_####________________ 
 * @__________####__###########_####_______________ 
 * @________#####___###########__#####_____________ 
 * @_______######___###_########___#####___________ 
 * @_______#####___###___########___######_________ 
 * @______######___###__###########___######_______ 
 * @_____######___####_##############__######______ 
 * @____#######__#####################_#######_____ 
 * @____#######__##############################____ 
 * @___#######__######_#################_#######___ 
 * @___#######__######_######_#########___######___ 
 * @___#######____##__######___######_____######___ 
 * @___#######________######____#####_____#####____ 
 * @____######________#####_____#####_____####_____ 
 * @_____#####________####______#####_____###______ 
 * @______#####______;###________###______#________ 
 * @________##_______####________####______________ 
 * @
 * @Author: ipk518 121206530@qq.com
 * @Date: 2025-05-30 14:55:45
 * @LastEditors: ipk518 121206530@qq.com
 * @LastEditTime: 2025-10-14 15:32:29
 * @FilePath: /etws-sxk2307/src/gnss/gnss.h
 * @Description: 
 * @你把时间投在专业上，两三年，你就能在圈子里小有名气。四五年，你就能靠这个专业赚钱。过了10年以上，你就能成为这个领域的专家
 * @Copyright (c) 2025 by etws@quyujiang, All Rights Reserved. 
 */

#ifndef __GNSS_H__

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "Common.h"
#include <atomic>
#include "../../Middlewares/dataTransmission/uartLite/uartLite.h"
#include "../../Middlewares/dataTransmission/webTop/udpSession.h"


#define GNSS_NMEA_RMC_DATA_BYTE 13
#define GNSS_NMEA_GGA_DATA_BYTE 14

#pragma pack(push, 1)

struct gpsRegStatus
{
    uint16_t m_header;  //0x55aa
    uint8_t m_cmd;    //0x01
    uint16_t m_dataLen;   //0x69
    char m_utcTime[9]; // hhmmss.sss格式
    char m_validFlag;//A为有效V为无效，定位有效标志位
    char m_dLatitude[2];//纬度d
    char m_mLatitude[2];//纬度m
    char m_latiDecimal;//小数点
    char m_mmLatitude[5];//纬度mm
    char m_latiLocal;//纬度方向N北纬S南纬
    char m_dLongitude[3];//经度d
    char m_mLongitude[2];//经度m
    char m_mLongDecimal;//经度小数点
    char m_mmLongitude[5];//经度mm
    char m_longLocal;//经度方向E为东经W为西经
    char m_altitude[6];//高度
    uint32_t m_baseline; //32bit little-endian 基线距离
    uint32_t m_baselinePrec;//32bit little-endian 基线距离精度
    uint32_t m_azimuth;//32bit little-endian  方位角
    uint32_t m_azimuthPrec;//32bit little-endian  方位角精度
    char m_utcData[6];// DDMMYY格式
    struct gpsSensor m_sensor0;
    struct gpsSensor m_sensor1;
    struct gpsSensor m_sensor2;
    struct gpsSensor m_sensor3;
    struct gpsSensor m_sensor4;
    uint16_t m_crc;//校验字节低位在前
};




typedef struct
{
  struct
  {
    std::string utc_time;             // hhmmss.sss格式
    char location_status;      // A=定位，V=未定 ???????
    std::string latitude;            //纬度ddmm.mmmm，度分格 ???????(前导位数不足则补0)
    char latitude_latitude;    //纬度N(北纬)或S(南纬)
    std::string longitude;           //经度dddmm.mmmm，度分格 ???????(前导位数不足则补0)
    char longitude_latitude;   //经度E(东经)或W(西经)
    std::string speed;                // Knots( ???????节也 ???????1.852千米／小 ???????)
    std::string azimuth;              //方位角
    std::string utc_data;             // DDMMYY格式
    char magnetic_declination[4]; //磁偏角方向，E=东，W= ???????
    char magnetic_declination_latitude[4];
    char location_mode; // A=自动，D=差分，E=估测，N=数据无效(3.0协议内容)
    char navStatus;
  } gnrmc;
  struct
  {
    char utc_time[9];            
    char latitude[10];            
    char latitude_latitude;    
    char longitude[11];           
    char longitude_latitude;   
    char quality;
    char numSV[2];
    char hdop[4];
    char alt[6];
    char altunit;
    char sep[5];
    char sepUnit;
    char diffAge;
    char diffStation[2];
  } gngga;
  struct
  {
    uint32_t relPosLength; 
    uint32_t accLength;
    uint32_t relPosHeading;
    uint32_t accHeading;
  } ubx_nav_relposned;
  struct
  {
    uint16_t herder; 
    uint8_t  order_code;
    uint16_t length;
    uint8_t utc_time[9];
    uint8_t location_status;
    uint8_t latitude[10];            
    uint8_t latitude_latitude;    
    uint8_t longitude[11];           
    uint8_t longitude_latitude;
    uint8_t altitude[6];
    uint32_t relPosLength; 
    uint32_t accLength;
    uint32_t relPosHeading;
    uint32_t accHeading;
    uint8_t utc_data[6];
    uint16_t crc;
  } gnss_data_output;
} gnss_data_struct;



struct modbusResponse
{
    uint8_t modbusId;
    uint8_t functionCode;
    uint8_t dataLength;
    uint16_t data[85]; //85个寄存器
    uint8_t crc[2];
};

//REG 527-611,每个寄存器占2字节
struct gnssRTUData
{
  uint16_t fen[24];                   //风扇1-24速度反馈，占空比10%（19500-21200）占空比90%
  uint16_t utc_time[9];               //世界时	UTF-8	HHMMSSSSS(时分秒)              
  uint16_t location_status;           // 定位是否有效	UTF-8	A(有效) ro V(无效)
  uint16_t latitude[10];              // 纬度	UTF-8	度十进制表示法：40.712800
  uint16_t latitude_latitude;         // 纬度半球	UTF-8	S(南纬) ro N(北纬)
  uint16_t longitude[11];             // 经度	UTF-8	度十进制表示法：74.006000
  uint16_t longitude_latitude;        // 经度方向	UTF-8	E(东经) ro W(西经)
  uint16_t alt[6];                    // 海拔高度	UTF-8	单位：m
  int relPosLength;                   //两天线之间的距离
  int accLength;                      // 两天线之间的距离精度
  int relPosHeading;                  // 方位角
  int accHeading;                     // 方位角精度
  uint16_t utc_data[6];               // 世界日期	UTF-8	YYMMDD(年月日)
  short int sht35_temp;               // 温度	-20至80	单位：℃
  short int sht35_humi;               // 湿度	0至100	单位：%
  uint16_t board_12v_voltage;         // 5V电压	0至12000	单位：mV
  uint16_t board_5v_voltage;          // 3.3V电压	0至5000	单位：mV
  uint16_t board_3V3_voltage;         // 12V电压	0至3300	单位：mV
  uint16_t board_12v_current;         // 5V电流	0至2000	单位：mA
  uint16_t board_5v_current;          // 3.3V电流	0至2000	单位：mA
  uint16_t board_3v3v_current;        // 12V电流	0至2000	单位：mA
};

#pragma pack(pop)


class nmea0183Protocol
{
public:
    nmea0183Protocol();
    ~nmea0183Protocol();
public:

    void parse(const std::string& sentence, gnss_data_struct *gnssData);
    
private:
    unsigned char calculateChecksum(const std::string& sentence);
    std::vector<std::string> split(const std::string &s, char delimiter);
    bool parseRMC(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGGA(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGPGSV(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGPGLL(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGBGSV(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGAGSV(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
    bool parseGLGSV(const std::vector<std::string>& fields, gnss_data_struct *gnssData);
};

class gnss : public nmea0183Protocol
{
private:
    /* data */
public:
    gnss(/* args */);
    ~gnss();

public:
    bool Init(const char *uartName);
    void make();
    struct GpsUpdateStatus* Get();
    gnss_data_struct gnss_data;
private:
    uartLite* m_gnssUart;
    struct gpsRegStatus m_gnssStatus;
    struct GpsUpdateStatus m_update;

    bool m_threadRun;
    std::thread * m_gnssTh; /* 接收线程*/
    static void Task(gnss *args);
    
};


class gnssModbusRtu
{
public:
  gnssModbusRtu();
  ~gnssModbusRtu();

private:
  const char *dastIp = "192.168.23.19";
  const int udpPort = 62307;
  const uint8_t modbusId = 0x66;
  const uint8_t rFunctionCode = 0x03;
  const uint8_t wFunctionCode = 0x10;
  
  udpSession g_Sess;

  std::mutex sendMutex;
  std::atomic<bool> gnssIsInit{false}; 
public:
  uint8_t startReg[2];//高位在前，低位在后，符合MODBUS协议
  uint8_t regNum[2];//高位在前，低位在后，符合MODBUS协议
  uint8_t crc[2];
  uint8_t readCmd[8];
  uint8_t writeCmd[100];
  int m_gnssPort = 0;
  int m_gnssIp = 0;
  struct modbusResponse response;
  struct gnssRTUData m_gnssAll;
  struct gnssUpdateRtu m_update;
public:
  static gnssModbusRtu& Instance();
  bool Init(const char *ip,int port);
  int Send(uint8_t *data, int len);
  void Recv(unsigned char *data, int len);
  void getData(gnssUpdateRtu *data);
  void read(uint16_t reg = 527, uint16_t num = 85);
  void write(uint16_t reg, uint16_t num, uint16_t *data);
  void getSpecificReg(uint16_t reg, uint16_t *data, uint16_t num);
};


#endif // !__GNSS_H__

